master
  1---
  2import { siteConfig } from '@/config';
  3import BackLinks from '@components/misc/BackLinks.astro';
  4import License from '@components/misc/License.astro';
  5import PostInfo from '@components/misc/PostInfo.astro';
  6import ImageWrapper from '@components/utils/ImageWrapper.astro';
  7import Markdown from '@components/utils/Markdown.astro';
  8import PostPageLayout from '@layouts/PostPageLayout.astro';
  9import { getAllReferences, getPosts } from '@utils/content-utils';
 10import { t } from '@utils/i18n';
 11import { Icon } from 'astro-icon/components';
 12import { render } from 'astro:content';
 13
 14export async function getStaticPaths() {
 15  const posts = await getPosts();
 16  return posts.map((article) => ({
 17    params: { article: article.data.slug },
 18    props: { article },
 19  }));
 20}
 21
 22const { article } = Astro.props;
 23const { Content, headings, remarkPluginFrontmatter } = await render(article);
 24const description = article.data.description || remarkPluginFrontmatter.excerpt;
 25const isDraft = article.data.draft === true;
 26
 27const allReferences = await getAllReferences();
 28const allRefByCurrent = allReferences.filter((it) => it.refBy.id === article.id);
 29const allRefToCurrent = allReferences.filter((it) => it.refTo.id === article.id);
 30
 31const references: {
 32  reference: string;
 33  context: string;
 34  id: string;
 35}[] =
 36  (
 37    remarkPluginFrontmatter.references as {
 38      reference: string;
 39      context: string;
 40      id: string;
 41    }[]
 42  )?.map((it) => ({
 43    reference: it.reference.split('#')[0],
 44    context: it.context,
 45    id: it.id,
 46  })) || [];
 47
 48const backLinks: {
 49  refBy: {
 50    title: string;
 51    collection: 'posts' | 'spec';
 52    id: string;
 53  };
 54  context: string;
 55  offset: [number, number];
 56  id: string;
 57}[] = allRefToCurrent;
 58---
 59
 60<PostPageLayout
 61  title={article.data.title}
 62  description={description}
 63  headings={headings}
 64  comment={article.data.comment}
 65  lang={article.data.lang}
 66  banner={typeof article.data.cover === 'string' ? article.data.cover : article.data.cover?.src}
 67>
 68  <Fragment slot="header-content">
 69    <PostInfo
 70      title={article.data.title}
 71      publishedAt={article.data.published}
 72      category={article.data.category}
 73      tags={article.data.tags}
 74      wordCount={remarkPluginFrontmatter.words}
 75      readingTime={remarkPluginFrontmatter.minutes}
 76      lang={article.data.lang}
 77      class="mx-2 mt-4 overflow-y-scroll"
 78      style={siteConfig.banner !== false ? `max-height: ${siteConfig.banner.postHeight}` : null}
 79    />
 80  </Fragment>
 81  {
 82    siteConfig.banner === false && article.data.cover && (
 83      <ImageWrapper
 84        src={article.data.cover}
 85        class="mb-6 rounded-xl shadow"
 86        alt={article.data.title}
 87      />
 88    )
 89  }
 90  <Markdown
 91    bidirectional-references={{
 92      references,
 93      allRefByCurrent,
 94    }}
 95  >
 96    {
 97      isDraft && (
 98        <blockquote class="collapse-arrow collapse" data-callout="note">
 99          <input type="checkbox" checked="true" />
100          <div class="callout-title collapse-title">
101            <Icon name="mingcute:pencil-line" />
102            NOTE
103          </div>
104          <div class="collapse-content">
105            <Fragment
106              set:html={t.info.devNote({
107                configKey: 'buildConfig.showDraftsOnDev',
108                configValue: false,
109                configFilePath: 'src/config.ts',
110              })}
111            />
112          </div>
113        </blockquote>
114      )
115    }
116    <Content />
117  </Markdown>
118  <License time={article.data.published} lang={article.data.lang} />
119  {backLinks.length > 0 && <BackLinks backLinks={backLinks} />}
120</PostPageLayout>